package com.yantong.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.yantong.constant.StringConstans;
import com.yantong.constant.WxTerminal;
import com.yantong.exception.BDException;
import com.yantong.mapper.MemberWxcardMapper;
import com.yantong.pojo.*;
import com.yantong.service.CacheDataService;
import com.yantong.service.CentreService;
import com.yantong.service.WxService;
import com.yantong.utils.ValidateUtil;
import com.yantong.utils.WxRedisKeyHelper;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class WxServiceImpl implements WxService {
	private static final Logger LOGGER = LoggerFactory.getLogger(WxServiceImpl.class);
	@Value("${spring.redis.host}")
	private String host = "127.0.0.1";
	@Value("${spring.redis.port}")
	private int port = 6379;
	//timeout for jedis try to connect to redis server, not expire time! In milliseconds
//	@Value("${spring.redis.timeout}")
	private int timeout = 0;
	@Value("${spring.redis.password}")
	private String password;

	@Autowired
	private CacheDataService cacheDataService;
	@Autowired
	private MemberWxcardMapper memberWxcardMapper;
	@Autowired
	private CentreService centreService;
	@Autowired
	@Lazy
	private WxService wxService;

	@Autowired
	private StringRedisTemplate redisTemplate;

	public String getAppId(Long certerId, int terminal) {
		String appId = StringConstans.STR_EMPTY;
		Centre centre = centreService.getByKey(certerId);
		if (centre == null) {
			centre = centreService.getPlatCenter();
		}
		if (null != centre) {
			if (WxTerminal.TERMINAL_GZH.getTerminal() == terminal) {
				appId = centre.getGzhAppid();
			} else if (WxTerminal.TERMINAL_XCX.getTerminal() == terminal) {
				appId = centre.getRelateAccount();
			}
		}
		return appId;
	}

	public String getSecret(Long certerId, int terminal) {
		String secret = StringConstans.STR_EMPTY;
		Centre centre = centreService.getByKey(certerId);
		if (centre == null) {
			centre = centreService.getPlatCenter();
		}
		if (null != centre) {
			if (WxTerminal.TERMINAL_GZH.getTerminal() == terminal) {
				secret = centre.getGzhSecret();
			} else if (WxTerminal.TERMINAL_XCX.getTerminal() == terminal) {
				secret = centre.getAccountTel();
			}
		}
		return secret;
	}

	@Override
	public String getAccessToken(Long centreId, int terminal) {
		if(centreId == null){
			throw new BDException("公众号商户信息有误，请联系管理员！");
		}
		String gzhAccessTokenKey = WxRedisKeyHelper.getGzhAccessTokenKey(centreId);
		//从缓存里面获取
		String accessToken = redisTemplate.opsForValue().get(gzhAccessTokenKey);
		LOGGER.info("缓存中获取的公众号accessToken：：：" + accessToken);
		try {
			//缓存中不存在，则要重新请求
			if (ValidateUtil.isEmptyString(accessToken)) {
				String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + getAppId(centreId, terminal) + "&secret=" + getSecret(centreId, terminal);
				HttpClient httpClient = new HttpClient();
				GetMethod getMethod = new GetMethod(url);
				int execute = httpClient.executeMethod(getMethod);
				System.out.println("execute:" + execute);
				String accessTokenStr = getMethod.getResponseBodyAsString();
				LOGGER.info("accessTokenObj公众号请求返回结果：" + accessTokenStr);
				if (ValidateUtil.isNotEmptyString(accessTokenStr)) {
					JSONObject accessTokenObj = JSONObject.parseObject(accessTokenStr);
					accessToken = accessTokenObj.getString("access_token");
					LOGGER.info("重新请求公众号的accessToken:::" + accessToken);
					//设置到缓存中，有效时间为7190s，因为微信的失效时间为7200s
					if (ValidateUtil.isNotEmptyString(accessToken)) {
						redisTemplate.opsForValue().set(gzhAccessTokenKey, accessToken, 7190, TimeUnit.SECONDS);
					}
				}
			}
		} catch (IOException e) {
			LOGGER.info("getAccessToken failed,desc:::" + e);
			e.printStackTrace();
		}

		return accessToken;
	}

	@Override
	public String getJsapiTicket(Long centerId, int terminal) {
		String accessToken = getAccessToken(centerId, terminal);
		String jsapiTicketKey = WxRedisKeyHelper.getJsapiTicketKey(centerId);
		String jsapiTicket = cacheDataService.getStringValue(jsapiTicketKey);
		LOGGER.info("===从缓存中获取的的jsapi_ticket(jsapi)===" + jsapiTicket);
		if (ValidateUtil.isEmptyString(jsapiTicket)) {
			try {
				if (ValidateUtil.isNotEmptyString(accessToken)) {
					String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=jsapi";
					HttpClient httpClient = new HttpClient();
					GetMethod getMethod = new GetMethod(url);
					int execute = httpClient.executeMethod(getMethod);
					System.out.println("execute:" + execute);
					String jsApiTicketStr = getMethod.getResponseBodyAsString();
					LOGGER.info("jsApiTicket请求返回结果：" + jsApiTicketStr);
					if (ValidateUtil.isNotEmptyString(jsApiTicketStr)) {
						JSONObject jsApiTicketObj = JSONObject.parseObject(jsApiTicketStr);
						jsapiTicket = jsApiTicketObj.getString("ticket");
						LOGGER.info("jsApiTicket:::" + jsapiTicket);//设置到缓存中，有效时间为7190s，因为微信的失效时间为7200s
						cacheDataService.setCache(jsapiTicketKey, jsapiTicket, 7100, TimeUnit.SECONDS);
					}
				}
			} catch (IOException e) {
				LOGGER.info("get jsApiTicket failed,desc:::" + e);
				e.printStackTrace();
			}
		}
		return jsapiTicket;
	}

	@Override
	public String getCardApiTicket(Long centerId) {
		String accessToken = getAccessToken(centerId, WxTerminal.TERMINAL_GZH.getTerminal());
		String jsapiTicketKey = WxRedisKeyHelper.getCardApiTicketKey(centerId);
		String jsapiTicket = cacheDataService.getStringValue(jsapiTicketKey);
		LOGGER.info("===从缓存中获取的的jsapi_ticket(wx_card)===" + jsapiTicket);
		if (ValidateUtil.isEmptyString(jsapiTicket)) {
			try {
				if (ValidateUtil.isNotEmptyString(accessToken)) {
					String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken + "&type=wx_card";
					HttpClient httpClient = new HttpClient();
					GetMethod getMethod = new GetMethod(url);
					int execute = httpClient.executeMethod(getMethod);
					System.out.println("execute:" + execute);
					String jsApiTicketStr = getMethod.getResponseBodyAsString();
					LOGGER.info("jsApiTicket请求返回结果：" + jsApiTicketStr);
					if (ValidateUtil.isNotEmptyString(jsApiTicketStr)) {
						JSONObject jsApiTicketObj = JSONObject.parseObject(jsApiTicketStr);
						jsapiTicket = jsApiTicketObj.getString("ticket");
						LOGGER.info("jsApiTicket:::" + jsapiTicket);//设置到缓存中，有效时间为7190s，因为微信的失效时间为7200s
						cacheDataService.setCache(jsapiTicketKey, jsapiTicket, 7100, TimeUnit.SECONDS);
					}
				}
			} catch (IOException e) {
				LOGGER.info("get jsApiTicket failed,desc:::" + e);
				e.printStackTrace();
			}
		}
		return jsapiTicket;
	}

	public Map<String, String> getWxCardConfig(Long centerId, String cardId) {
		Map<String, String> wxParams = new HashMap<String, String>();
		try {
			LOGGER.info("centerId==:::::" + centerId);
			LOGGER.info("cardId:::" + cardId);
			wxParams.put("cardId", cardId);
			String nonceStr = createNonceStr();
			LOGGER.info("noncestr:::" + nonceStr);
			wxParams.put("noncestr", nonceStr);
			String timestamp = createTimestamp();
			LOGGER.info("timestamp:::" + timestamp);
			wxParams.put("timestamp", timestamp);
			String cardApiTicket = getCardApiTicket(centerId);
			wxParams.put("apiTicket", cardApiTicket);
			LOGGER.info("cardApiTicket:::" + cardApiTicket);

			//将api_ticket
			// timestamp:时间戳，商户生成从1970年1月1日00:00:00至今的秒数,即当前的时间,且最终需要转换为字符串形式;由商户生成后传入,不同添加请求的时间戳须动态生成，若重复将会导致领取失败！。
			// card_id:指定卡券的ID
			// code:指定的卡券code码，只能被领一次。自定义code模式的卡券必须填写，非自定义code和预存code模式的卡券不必填写。详情见： 是否自定义code码
			// openid:指定领取者的openid，只有该用户能领取。bind_openid字段为true的卡券必须填写，bind_openid字段为false不必填写。
			// nonce_str:随机字符串，由开发者设置传入， 加强安全性（若不填写可能被重放请求） 。随机字符串，不长于32位。推荐使用大小写字母和数字，不同添加请求的nonce须动态生成，若重复将会导致领取失败。
			// 的value值进行字符串的字典序排序
			Collection<String> values = wxParams.values();
			String[] valueArray = values.toArray(new String[values.size()]);
			Arrays.sort(valueArray);
			StringBuilder sb = new StringBuilder();
			for (String value : valueArray) {
				sb.append(value);
			}

			//将所有参数字符串拼接成一个字符串进行sha1加密，得到signature
			String cardSignStr = sb.toString();
			LOGGER.info("cardSignStr:::::" + cardSignStr);
			MessageDigest crypt = MessageDigest.getInstance("SHA-1");
			crypt.reset();
			crypt.update(cardSignStr.getBytes("UTF-8"));
			String signature = byteToHex(crypt.digest());
			LOGGER.info("signature:::::" + signature);
			wxParams.put("signature", signature);

			String appId = getAppId(centerId, WxTerminal.TERMINAL_GZH.getTerminal());
			wxParams.put("appId", appId);
			LOGGER.info("appId:::::" + appId);
		} catch (Exception e) {
			LOGGER.info("调用微信配置参数失败.", e);
		}
		return wxParams;
	}

	/**
	 * 产生随机串--由程序自己随机产生
	 */
	private static String createNonceStr() {
		return UUID.randomUUID().toString();
	}

	/**
	 * 由程序自己获取当前时间
	 */
	private static String createTimestamp() {
		return Long.toString(System.currentTimeMillis() / 1000);
	}

	/**
	 * 随机加密
	 *
	 * @param hash
	 * @return
	 */
	private static String byteToHex(final byte[] hash) {
		Formatter formatter = new Formatter();
		for (byte b : hash) {
			formatter.format("%02x", b);
		}
		String result = formatter.toString();
		formatter.close();
		return result;
	}

	public String createCard(Long centreId, String content) {
		String accessToken = getAccessToken(centreId, WxTerminal.TERMINAL_GZH.getTerminal());
		//1.创建卡券功能
		String url = "https://api.weixin.qq.com/card/create?access_token=" + accessToken;

		String returnData = response(url, content);
		LOGGER.info("卡券创建返回信息1：========" + returnData);
		JSONObject returnObj = JSONObject.parseObject(returnData);
		LOGGER.info("卡券创建返回信息2：========" + returnObj);
		return returnObj.getString("card_id");
	}

	/**
	 * 解密Card对应的Code
	 *
	 * @param centreId
	 * @param encryptCode
	 * @return
	 */
	@Override
	public String decryptCardCode(Long centreId, String encryptCode) {
		String url = "https://api.weixin.qq.com/card/code/decrypt?access_token=" + getAccessToken(centreId, WxTerminal.TERMINAL_GZH.getTerminal());
		Map<String, String> paramMap = new HashMap<>();
		paramMap.put("encrypt_code", encryptCode);
		String returnData = response(url, JSONObject.toJSONString(paramMap));
		JSONObject returnObj = JSONObject.parseObject(returnData);
		return returnObj.getString("code");
	}

	@Override
	public void addWxCardList(Member member, List<WxCard> wxCardList, int type) {
		LOGGER.info("进入后台卡券领取信息添加-----开始");
		if (ValidateUtil.isNotEmptyCollection(wxCardList)) {
			for (WxCard wxCard : wxCardList) {
				MemberWxcard memberWxcard = new MemberWxcard();
				if (type == 1) { //生成会员卡
					memberWxcard.setCardId(wxCard.getCardId());
					memberWxcard.setTeamId(wxCard.getTeamId());
					memberWxcard.setMid(member.getId());
					memberWxcard.setCentreId(member.getCentreId());
					memberWxcard.setType(1);
					memberWxcard.setCode(wxService.decryptCardCode(member.getCentreId(), wxCard.getCode()));
				} else if (type == 2) { //生成商户卡
					memberWxcard.setCardId(wxCard.getCardId());
					//memberWxcard.setTeamId(shopMemeber.getId());
					memberWxcard.setMid(member.getId());
					memberWxcard.setCentreId(member.getCentreId());
					memberWxcard.setType(2);
					memberWxcard.setCode(wxService.decryptCardCode(member.getCentreId(), wxCard.getCode()));
				}
				memberWxcardMapper.insertSelective(memberWxcard);
				LOGGER.info("进入后台卡券领取信息添加-----结束");
			}
		}
	}

	@Override
	public List<MemberWxcard> wxCardFlag(Member member, Long teamId, int type,String cardId) {
		MemberWxcardExample cardExample = new MemberWxcardExample();
		if (type == 1) { //查询会员卡
			cardExample.createCriteria().andTeamIdEqualTo(teamId).andMidEqualTo(member.getId()).andTypeEqualTo(1);
		} else if (type == 2) { //查询商户卡
			cardExample.createCriteria().andCentreIdEqualTo(member.getCentreId()).andMidEqualTo(member.getId()).andTypeEqualTo(2);
		}
		List<MemberWxcard> list = memberWxcardMapper.selectByExample(cardExample);
		if(ValidateUtil.isEmptyCollection(list)){
			JSONObject jsonObject = this.findCardById(member.getCentreId(),cardId,member.getOpenid());
			String listStr = jsonObject.getString("card_list");
			if(ValidateUtil.isNotEmptyString(listStr)){
				List<WxCardDetail> cardList = JSONObject.parseArray(listStr,WxCardDetail.class);
				if( cardList.size() > 0 ){
					WxCardDetail wxCardDetail = cardList.get(0);
					MemberWxcard memberWxcard = new MemberWxcard();
					memberWxcard.setCentreId(member.getCentreId());
					memberWxcard.setTeamId(teamId);
					memberWxcard.setMid(member.getId());
					memberWxcard.setCardId(wxCardDetail.getCard_id());
					memberWxcard.setCode(wxCardDetail.getCode());
					memberWxcard.setType(type);
					memberWxcardMapper.insertSelective(memberWxcard);
					list.add(memberWxcard);
				}
			}
		}
		return list;
	}

	private JSONObject findCardById(Long centreId, String cardId,String openId) {
		String accessToken = getAccessToken(centreId, WxTerminal.TERMINAL_GZH.getTerminal());
		//查询用户卡券
		String url = "https://api.weixin.qq.com/card/user/getcardlist?access_token=" + accessToken;

		Map<String,Object> map = new HashMap<>();
		map.put("openid",openId);
		map.put("card_id",cardId);
		String returnData = response(url, JSONObject.toJSONString(map));
		LOGGER.info("查询用户卡券返回信息1：========" + returnData);
		JSONObject returnObj = JSONObject.parseObject(returnData);
		LOGGER.info("查询用户卡券返回信息2：========" + returnObj);
		return returnObj;
	}

	@Override
	public String wxUploadImg(boolean isNetworkFile, String filePath, Long centreId, InputStream inputStream) {
		try {
			String accessToken = getAccessToken(centreId, WxTerminal.TERMINAL_GZH.getTerminal());//使用上面的方式获取到token

			// 上传文件请求路径
			String action = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token="
					+ accessToken + "&type=image";

			URL url = new URL(action);
			String result = null;
			File file = null;
			String fileName = StringConstans.STR_EMPTY;
			if (ValidateUtil.isNotEmptyString(filePath)) {
				if (!isNetworkFile) {
					file = new File(filePath);
					if (!file.exists() || !file.isFile()) {
						throw new IOException("上传的文件不存在");
					}
					fileName = file.getName();
				} else {
					String[] urlname = filePath.split("/");
					int len = urlname.length - 1;
					fileName = urlname[len];//获取文件名 
				}
			}

			HttpURLConnection con = (HttpURLConnection) url.openConnection();
			con.setRequestMethod("POST"); // 以Post方式提交表单，默认get方式
			con.setDoInput(true);
			con.setDoOutput(true);
			con.setUseCaches(false); // post方式不能使用缓存

			// 设置请求头信息
			con.setRequestProperty("Connection", "Keep-Alive");
			con.setRequestProperty("Charset", "UTF-8");
			// 设置边界
			String BOUNDARY = "----------" + System.currentTimeMillis();
			con.setRequestProperty("Content-Type", "multipart/form-data; boundary="
					+ BOUNDARY);

			// 请求正文信息
			// 第一部分：
			StringBuilder sb = new StringBuilder();
			sb.append("--"); // 必须多两道线
			sb.append(BOUNDARY);
			sb.append("\r\n");
			sb.append("Content-Disposition: form-data;name=\"file\";filename=\""
					+ fileName + "\"\r\n");
			sb.append("Content-Type:application/octet-stream\r\n\r\n");
			byte[] head = sb.toString().getBytes("utf-8");
			// 获得输出流
			OutputStream out = new DataOutputStream(con.getOutputStream());

			// 输出表头
			out.write(head);
			// 文件正文部分
			// 把文件已流文件的方式 推入到url中
			DataInputStream in;
			if (inputStream != null) {
				in = new DataInputStream(inputStream);
			} else {
				in = new DataInputStream(new FileInputStream(file));
			}

			int bytes = 0;
			byte[] bufferOut = new byte[1024];
			while ((bytes = in.read(bufferOut)) != -1) {
				out.write(bufferOut, 0, bytes);
			}
			in.close();

			// 结尾部分
			byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
			out.write(foot);
			out.flush();
			out.close();
			StringBuffer buffer = new StringBuffer();
			BufferedReader reader = null;

			try {
				// 定义BufferedReader输入流来读取URL的响应
				reader = new BufferedReader(new InputStreamReader(con
						.getInputStream()));
				String line = null;
				while ((line = reader.readLine()) != null) {
					buffer.append(line);
				}
				if (result == null) {
					result = buffer.toString();
				}
			} catch (IOException e) {
				System.out.println("发送POST请求出现异常！" + e);
				e.printStackTrace();
				throw new IOException("数据读取异常");
			} finally {
				if (reader != null) {
					reader.close();
				}
			}
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}




	@Override
	public List<MemberWxcard> selectbymidAndCentreIdAndType(Long mid, Long centreId, Integer type) {
		return memberWxcardMapper.selectbymidAndCentreIdAndType(mid, centreId, type);
	}


	public static String response(String url, String content) {
		String line = "";
		String message = "";
		String returnData = "";
//        boolean postState     = false;
		BufferedReader bufferedReader = null;

		try {
			URL urlObject = new URL(url);
			HttpURLConnection urlConn = (HttpURLConnection) urlObject.openConnection();
			urlConn.setDoOutput(true);
			/*设定禁用缓存*/
			urlConn.setRequestProperty("Cache-Control", "no-cache");
			/*维持长连接*/
			urlConn.setRequestProperty("Connection", "Keep-Alive");
			/*设置字符集*/
			urlConn.setRequestProperty("Charset", "UTF-8");
			/*设定输出格式为json*/
			urlConn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
			/*设置使用POST的方式发送*/
			urlConn.setRequestMethod("POST");
			/*设置不使用缓存*/
			urlConn.setUseCaches(false);
			/*设置容许输出*/
			urlConn.setDoOutput(true);
			/*设置容许输入*/
			urlConn.setDoInput(true);
			urlConn.connect();

			OutputStreamWriter outStreamWriter = new OutputStreamWriter(urlConn.getOutputStream(), "UTF-8");
			outStreamWriter.write(content);
			outStreamWriter.flush();
			outStreamWriter.close();

			/*若post失败*/
			if ((urlConn.getResponseCode() != 200)) {
				returnData = "{\"jsonStrStatus\":0,\"processResults\":[]}";
				message = "发送POST失败！" + "code=" + urlConn.getResponseCode() + "," + "失败消息：" + urlConn.getResponseMessage();
				// 定义BufferedReader输入流来读取URL的响应
				InputStream errorStream = urlConn.getErrorStream();

				if (errorStream != null) {
					InputStreamReader inputStreamReader = new InputStreamReader(errorStream, "utf-8");
					bufferedReader = new BufferedReader(inputStreamReader);

					while ((line = bufferedReader.readLine()) != null) {
						message += line;
					}
					inputStreamReader.close();
				}
				errorStream.close();
				System.out.println("发送失败！错误信息为：" + message);
			} else {
				/*发送成功返回发送成功状态*/
//                postState = true;

				// 定义BufferedReader输入流来读取URL的响应
				InputStream inputStream = urlConn.getInputStream();

				InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
				bufferedReader = new BufferedReader(inputStreamReader);

				while ((line = bufferedReader.readLine()) != null) {
					message += line;
				}
				returnData = message;
				inputStream.close();
				inputStreamReader.close();
				System.out.println("发送POST成功！返回内容为：" + returnData);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (bufferedReader != null) {
					bufferedReader.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
			return returnData;
		}
	}
}
